package com.liaoyifan.core.valid.validator;

import com.liaoyifan.core.constant.Constants;
import com.liaoyifan.core.model.CoreService;
import com.liaoyifan.core.util.SpringContext;
import com.liaoyifan.core.valid.Lang;
import com.liaoyifan.core.valid.Message;
import com.liaoyifan.core.valid.constraints.Invoke;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.lang.reflect.Method;
import lombok.extern.log4j.Log4j2;
import org.springframework.util.ReflectionUtils;

@SuppressWarnings("unused")
@Log4j2
public class InvokeValidator implements ConstraintValidator<Invoke, Object> {

    private Class<? extends CoreService<?, ?>> service;
    private String method;

    @Override
    public void initialize(Invoke constraintAnnotation) {
        this.service = constraintAnnotation.service();
        this.method = constraintAnnotation.method();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (value == null) return true;
        try {
            CoreService<?, ?> bean = SpringContext.getBean(service);
            Method target = ReflectionUtils.findMethod(bean.getClass(), method, value.getClass());
            if (target == null) {
                return Message.build(
                        "Method " + method + " not found on service " + service.getName(), context);
            }
            if (!String.class.equals(target.getReturnType())) {
                return Message.build("Method " + method + " return type must be String", context);
            }
            ReflectionUtils.makeAccessible(target);
            Object result = ReflectionUtils.invokeMethod(target, bean, value);
            if (result == null) {
                return Message.build("Method " + method + " return must not be null", context);
            }
            String message = (String) result;
            if (Lang.equals(message, Constants.TRUE)) {
                return true;
            }
            return Message.build(message, context);
        } catch (Exception e) {
            return Message.build(e.getMessage(), context);
        }
    }
}
